package com.example.config;

import com.example.handler.MyAccessDeniedHandler;
import com.example.service.MyUserDetailsService;
import com.example.util.MyPasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import javax.annotation.Resource;

/**
 * 自定义security安全认证时，需要继承WebSecurityConfigurerAdapter
 *
 * @EnableGlobalMethodSecurity(securedEnabled = true) :开启基于方法的权限管理
 * prePostEnabled = true: 开启前置请求处理器，用于权限认证的
 */
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private MyPasswordEncoder passwordEncoder;

    @Resource
    private MyUserDetailsService myUserDetailsService;

    @Resource
    private MyAccessDeniedHandler myAccessDeniedHandler;


    /**
     * 自定义认证管理
     *
     * @param auth 认证管理器，可以实现用户自定义认证，比如将用户信息保存到内存中、使用自定义的认证逻辑等
     * @throws Exception inMemoryAuthentication ：将用户信息保存到内存中
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService)
                .passwordEncoder(passwordEncoder);
    }

    /**
     * 针对http资源的管理
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * 自定义用户登录页面以及登录路劲等相关信息
         */
        http.formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/login")
                .usernameParameter("uname")
                .passwordParameter("psw")
                .successForwardUrl("/index")
        ;
        /**
         * 配置注销退出
         */
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login?logout");

        /**
         * 自定义http资源的管理
         * 先配置不需要认证的，再配置需要特殊角色信息的资源，再配置默认只需要认证的
         * hasRole: 要求访问资源时，用户必须具有相应的角色信息（权限）
         * hasAnyRole ：要求访问资源时，用户必须具有相应的角色信息之一即可（权限）
         */
        http.authorizeRequests()
                .antMatchers("/login", "/index")
                .permitAll()   //允许所有用户访问
                .antMatchers("/vip")
                .hasRole("ADMIN")
                .antMatchers("/normal")
                .hasAnyRole("ADMIN", "USER")
                .anyRequest()
                .authenticated();
        /**
         * 启用记住我功能
         * 自动生成一个token（remember-me），保存到cookie中，当用户关闭浏览器后重新打开访问时，
         * 会自动传递，服务端会根据key以及base64算法解析，进行比对
         */
        http.rememberMe()
                .key("salt")
                .tokenValiditySeconds(120)
        ;


        //使用自定义403访问拒绝异常处理器
        http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);

        //关闭csrf防御机制
        http.csrf().disable();

    }
}
